﻿// -----------------------------------------------------------------------
// <copyright file="LogFileWatcher.cs" company="Microsoft">
//  OK
// </copyright>
// -----------------------------------------------------------------------

namespace Eeeek.TriggeredActions
{
    using System;
    using System.IO;

    /// <summary>
    /// An implementation of the ILogFileWatcher
    /// </summary>
    public class LogFileWatcher : FileSystemWatcher
    {
        /// <summary>
        /// Stores the byte that was previously the end of the file;
        /// </summary>
        private long formerLastByteNumber;

        /// <summary>
        /// Flag to determine if a file read is in process
        /// </summary>
        private bool isReading;

        /// <summary>
        /// The backing store for the Trigger property
        /// </summary>
        private string trigger;

        /// <summary>
        /// Gets or sets the trigger.
        /// </summary>
        /// <value>
        /// The trigger.
        /// </value>
        public string Trigger
        {
            get
            {
                return !string.IsNullOrWhiteSpace(this.trigger) ? this.trigger.ToUpper() : string.Empty;
            }

            set
            {
                this.trigger = value;
            }
        }

        /// <summary>
        /// Called when [file changed].
        /// </summary>
        /// <param name="e">The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.</param>
        /// <returns>True or False if trigger was found</returns>
        public bool FileChangeIncludesTrigger(FileSystemEventArgs e)
        {
            if (!this.isReading)
            {
                this.isReading = true;

                // Need to get only new content (line)
                if (e.ChangeType == WatcherChangeTypes.Changed)
                {
                    using (var reader = new StreamReader(new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
                    {
                        // read as far as the previous end of file
                        if (reader.BaseStream.CanRead && reader.BaseStream.CanSeek)
                        {
                            reader.BaseStream.Seek(this.formerLastByteNumber, SeekOrigin.Begin);
                            string line;
                            while ((line = reader.ReadLine()) != null)
                            {
                                if (line.ToUpper().Contains(this.Trigger))
                                {
                                    this.formerLastByteNumber = reader.BaseStream.Length;
                                    this.isReading = false;
                                    return true;
                                }
                            }
                        }

                        this.formerLastByteNumber = reader.BaseStream.Length;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Creates the file watcher.
        /// </summary>
        /// <param name="file">The file.</param>
        public void Start(FileInfo file)
        {
            // Find end of file
            using (var fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
            using (var reader = new StreamReader(fileStream))
            {
                this.formerLastByteNumber = reader.BaseStream.Length;
            }
        }
    }
}
